// (c) 2004-2005 Wout de Zeeuw

using System;
using System.Collections;
using System.Resources;
using System.Windows.Forms;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;

namespace CaveArt.UIcomp
{
	/// <summary>
	/// Allows tabbing through items and has globalized tooltips.
	/// </summary>
	public class CustomPropertyGrid : PropertyGrid
	{
		private ResourceManager			rm = null;
	    private bool					expandOnTab = false;
		private Control					nextcontrol = null;
		public event EventHandler		OnLastField = null;
		
		public CustomPropertyGrid() : base() 
		{
	        Refresh();
	    }
        
        /// <summary>
        /// Gets or sets whether to expand an item when pressing tab.
        /// </summary>
        /// <remarks>
        /// When <c>true</c> items are also unexpanded when pressing shift-tab.
        /// Note that the enter key will always work to expand.
        /// </remarks>
        public bool ExpandOnTab {
        	get {
        		return expandOnTab;
        	}
        	set {
        		expandOnTab = value;
        	}
        }

		public Control NextControl
		{
			get { return nextcontrol;	}
			set { nextcontrol = value;	}
		}

	    /// <summary>
	    /// Refresh.
	    /// </summary>
	    /// <remarks>
	    /// Sets up globalized tooltips for "Categorized" and
	    /// "Alphabetic".
	    /// </remarks>
	    public override void Refresh() {
	        if (rm == null) {
	            rm = new ResourceManager(this.GetType());
	        }
	        // Find ToolBar in Controls.
	        foreach (Control control in Controls) {
	            if (control is ToolBar) {
	                ToolBar toolBar = control as ToolBar;
	                foreach (ToolBarButton button in toolBar.Buttons) {
	                    // Hacked, but no other way to do it.
	                    // As soon as MS decides to change the implementation
	                    // this will break ofcourse.
	                    switch (button.ImageIndex) {
	                        case 0 :
	                            button.ToolTipText = rm.GetString("Alphabetic.ToolTip");
	                            break;
	                        case 1 :
	                            button.ToolTipText = rm.GetString("Categorized.ToolTip");
	                            break;
	                        case 3 :
	                            button.ToolTipText = rm.GetString("PropertyPages.ToolTip");
	                            break;
	                    }
	                }
	            }
	        }
	        base.Refresh();
	    }

	    protected override void OnPropertyValueChanged(
           PropertyValueChangedEventArgs e
       ) {
            base.OnPropertyValueChanged(e);
       }

		public void SelectFirstItem()
		{
			GridItem selectedItem = SelectedGridItem;
			GridItem root = selectedItem;

			if ( root != null )
			{
				while ( root.Parent != null )
				{
					root = root.Parent;
				}

				// Find all expanded items and put them in a list.
				ArrayList items = new ArrayList();
				AddExpandedItems(root, items);

				if ( items.Count > 0 )
				{
					SelectedGridItem = (GridItem)items[0]; // select the first grid item
				}
			}
		}

		// Do special processing for Tab key.
		protected override bool ProcessCmdKey(ref Message msg, Keys k)
		{
			bool bRet				= false;
			bool bShift				= ((k & Keys.Shift) == Keys.Shift);
			GridItem selectedItem	= SelectedGridItem;
			GridItem root			= selectedItem;
				
			if (selectedItem != null) 
			{
				while (root.Parent != null) 
				{
					root = root.Parent;
				}

				// Find all expanded items and put them in a list.
				ArrayList items = new ArrayList();
				AddExpandedItems(root, items);
			    
				
				int foundIndex = items.IndexOf(selectedItem);

				switch ( k )
				{
					case Keys.Enter:
					case Keys.Tab:						// k == (Keys.Tab | Keys.Shift)
						#region (ENTER or Tab with Shift and without Shift)
						if ( bShift ) 
						{
							foundIndex--;
							if (foundIndex < 0) 
							{
								foundIndex = items.Count - 1;
							}
							SelectedGridItem = (GridItem)items[foundIndex];
							if (expandOnTab && (SelectedGridItem.GridItems.Count > 0))
							{
								SelectedGridItem.Expanded = false;
							}
						}
						else 
						{
							foundIndex++;
							if (foundIndex >= items.Count) 
							{			
								if ( OnLastField != null )
								{
									OnLastField(this, new EventArgs());
									return true;
								}
								
								if ( NextControl != null )
								{
									NextControl.Focus();
								}

								foundIndex = 0;
								SelectedGridItem = (GridItem) items[foundIndex];
							}
							else
							{
								SelectedGridItem = (GridItem)items[foundIndex];
								if (expandOnTab && (SelectedGridItem.GridItems.Count > 0))
								{
									SelectedGridItem.Expanded = true;
								}						
							}
						}
						bRet = true;
						#endregion
						break;
					case Keys.Up:
						#region UP
						foundIndex--;
						if (foundIndex < 0) 
						{
							foundIndex = items.Count - 1;
						}
						SelectedGridItem = (GridItem)items[foundIndex];
						if (expandOnTab && (SelectedGridItem.GridItems.Count > 0))
						{
							SelectedGridItem.Expanded = false;
						}
						bRet = true;
						#endregion
						break;
					case Keys.Down:
						#region DOWN
						foundIndex++;
						if (foundIndex >= items.Count) 
						{							
							foundIndex = 0;
							SelectedGridItem = (GridItem)items[foundIndex];

							if (NextControl != null)
							{
								NextControl.Focus();								
							}
						}
						else
						{
							SelectedGridItem = (GridItem)items[foundIndex];
							if (expandOnTab && (SelectedGridItem.GridItems.Count > 0))
							{
								SelectedGridItem.Expanded = true;
							}						
						}
						bRet = true;
						#endregion
						break;
					case Keys.Add:
					case Keys.Oemplus:
						//TODO: when '+' key pressed, it needs to be cahnged to go to the next tax style index)
//						if ( SelectedGridItem != null ) 
//						{
//							SelectedGridItem.Select();
//						}
						break;
				}
			}

			return (bRet) ? true : base.ProcessCmdKey(ref msg, k);
		}

		private void AddExpandedItems(GridItem parent, IList items) {
			if (parent.PropertyDescriptor != null) {
				items.Add(parent);
			}
			if (parent.Expanded) {
				foreach (GridItem child in parent.GridItems) {
					AddExpandedItems(child, items);
				}
			}
		}

		private void InitializeComponent()
		{
			// 
			// CustomPropertyGrid
			// 
			this.SelectedGridItemChanged += new System.Windows.Forms.SelectedGridItemChangedEventHandler(this.CustomPropertyGrid_SelectedGridItemChanged);
		}

		private void CustomPropertyGrid_SelectedGridItemChanged(object sender, System.Windows.Forms.SelectedGridItemChangedEventArgs e)
		{
			e.NewSelection.Select(); 
		}
	}
}

